/*
 * Freeswitch Modular Media Switching Software Library / Soft-Switch Application
 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
 * Copyright (C) 2020-2023, Yantai XiaoYintao Inc.
 *
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
 *
 * The Initial Developer of the Original Code is
 * Seven Du <dujinfang@x-y-t.cn>
 * Portions created by the Initial Developer are Copyright (C)
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Seven Du <dujinfang@x-y-t.cn>
 * Kai Wang <wangkai@x-y-t.cn>
 * Chao Dong <dongchao@x-y-t.cn>
 *
 * mod_srs.c srs RTC Endpoint
 *
 */
#include "mod_srs.h"

SWITCH_MODULE_LOAD_FUNCTION(mod_srs_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_srs_shutdown);

SWITCH_MODULE_DEFINITION(mod_srs, mod_srs_load, mod_srs_shutdown, NULL);

mod_srs_globals_t mod_srs_globals;

switch_xml_binding_t *xml_bindings = NULL;

static switch_status_t config(switch_memory_pool_t *pool)
{
	switch_xml_t cfg, xml, settings, bindings, binding, param;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int count = 0;

	mod_srs_globals.node_name = switch_core_get_variable_pdup("core_uuid", pool);


	if (!(xml = switch_xml_open_cfg("srs.conf", &cfg, NULL))) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of srs.conf failed\n");
		return SWITCH_STATUS_TERM;
	}

	if ((settings = switch_xml_child(cfg, "settings"))) {
		for (param = switch_xml_child(settings, "param"); param; param = param->next) {
			char *var = NULL;
			char *val = NULL;

			var = (char *)switch_xml_attr_soft(param, "name");
			val = (char *)switch_xml_attr_soft(param, "value");

			if (!strcasecmp(var, "debug")) {
				if (val) {
					mod_srs_globals.debug = atoi(val);
				}
			} 
		}
	}
	if ((bindings = switch_xml_child(cfg, "bindings"))) {
		for (binding = switch_xml_child(bindings, "param"); binding; binding = binding->next) {
			srs_bind_event_t *bevent = &mod_srs_globals.bind_events[count];

			char *event_name = (char *)switch_xml_attr_soft(binding, "name");
			char *sub_name = (char *)switch_xml_attr_soft(binding, "subclass");

			if (!zstr(event_name)) {
				bevent->event_name = switch_core_strdup(mod_srs_globals.pool, event_name);

				if (!zstr(sub_name)) {
					bevent->sub_name = switch_core_strdup(mod_srs_globals.pool, sub_name);
				}
			}

			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "bind to event %s %s\n", bevent->event_name, switch_str_nil(bevent->sub_name));



			if (!zstr(bevent->event_name)) {
				count++;
			} else {
				bevent->sub_name = NULL;
			}

			if (count >= MAX_BIND_EVENT) break;
		}
	}

	switch_xml_free(xml);

	return status;
}


SWITCH_STANDARD_API(srs_function)
{
	char *argv[1024] = {0};
	int argc = 0;
	char *mycmd = NULL;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	static const char usage_string[] = "USAGE:\n"
									   "--------------------------------------------------------------------------------\n"
									   "srs [debug <on [1-10]|off>]\n"
									   "srs help\n"
									   "--------------------------------------------------------------------------------\n";

	if (zstr(cmd)) {
		stream->write_function(stream, "%s", usage_string);
		goto done;
	}

	if (!(mycmd = strdup(cmd))) {
		status = SWITCH_STATUS_MEMERR;
		goto done;
	}

	if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
		stream->write_function(stream, "%s", usage_string);
		goto done;
	}

	if (!strcasecmp(argv[0], "help")) {
		stream->write_function(stream, "%s", usage_string);
		goto done;
	} else if ((!strcasecmp(argv[0], "debug")) && (!argv[1])) {
		stream->write_function(stream, "+OK debug %s\n", mod_srs_globals.debug ? "on" : "off");
	} else if ((!strcasecmp(argv[0], "debug")) && (!strcasecmp(argv[1], "off"))) {
		mod_srs_globals.debug = 0;
		stream->write_function(stream, "+OK debug off\n");
		goto done;
	} else if ((!strcasecmp(argv[0], "debug")) && (!strcasecmp(argv[1], "on"))) {
		int level = 10;
		if (argc > 2) {
			level = atoi(argv[2]);

			if (level < 0) level = 0;
			if (level > 10) level = 10;
		}

		mod_srs_globals.debug = level;

		if (level == 0) {
			stream->write_function(stream, "+OK debug off\n");
		} else {
			stream->write_function(stream, "+OK debug on %d\n", level);
		}
	} else {
		stream->write_function(stream, "Unknown Command [%s]\n", argv[0]);
	}

done:
	switch_safe_free(mycmd);
	return status;
}

SWITCH_MODULE_LOAD_FUNCTION(mod_srs_load)
{

	switch_api_interface_t *api_interface = NULL;

	/* connect my internal structure to the blank pointer passed to me */
	*module_interface = switch_loadable_module_create_module_interface(pool, modname);

	SWITCH_ADD_API(api_interface, "srs", "srs api", srs_function, "syntax");
	switch_console_set_complete("add srs help");
	switch_console_set_complete("add srs debug on");
	switch_console_set_complete("add srs debug off");

	memset(&mod_srs_globals, 0, sizeof(mod_srs_globals));
	mod_srs_globals.pool = pool;
	mod_srs_globals.uuid = switch_core_strdup(pool, switch_core_get_uuid());
	mod_srs_globals.node_ip = switch_core_get_variable_pdup("local_ip_v4", pool);


	switch_mutex_init(&mod_srs_globals.sps_mutex, SWITCH_MUTEX_NESTED, pool);
	switch_mutex_init(&mod_srs_globals.cache_mutex, SWITCH_MUTEX_NESTED, pool);

	const char *err = NULL;
	if (switch_xml_reload(&err) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "xml reload error: %s\n", err);
	} else {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "xml reload OK\n");
	}

	config(pool);


	verto_load(module_interface, pool);


	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SRS version: %s Started\n", srs_version());

	/* indicate that the module should continue to be loaded */
	return SWITCH_STATUS_SUCCESS;
}

/*
  Called when the system shuts down
*/
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_srs_shutdown)
{
	if (xml_bindings) {
        switch_xml_unbind_search_function(&xml_bindings);
    }

	verto_shutdown();

	return SWITCH_STATUS_SUCCESS;
}

SWITCH_MODULE_RUNTIME_FUNCTION(mod_srs_runtime)
{
	if (!mod_srs_globals.dial_queue) {
		return SWITCH_STATUS_TERM;
	}

	switch_time_t ts = 0, reference = switch_time_now() + 1000000;

	mod_srs_globals.sps_total = 0;
	switch_core_session_ctl(SCSC_SPS, &mod_srs_globals.sps_total);
	mod_srs_globals.sps = mod_srs_globals.sps_total * 0.9;

	while (mod_srs_globals.running) {
		ts = switch_time_now();

		if (ts > reference) {
			reference = switch_time_now() + 1000000;
			switch_mutex_lock(mod_srs_globals.sps_mutex);
			mod_srs_globals.sps = mod_srs_globals.sps_total * 0.9;
			switch_mutex_unlock(mod_srs_globals.sps_mutex);
		}

		switch_yield(1000);
	}

	return SWITCH_STATUS_TERM;
}



/* For Emacs:
 * Local Variables:
 * mode:c
 * indent-tabs-mode:nil
 * tab-width:4
 * c-basic-offset:4
 * End:
 * For VIM:
 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet expandtab:
 */
